import { Body, Controller, Get, Param, Post, Query, Res, UploadedFile, UseGuards, UseInterceptors } from "@nestjs/common";
import { AuthGuard } from "@nestjs/passport";
import { ApiOperation, ApiTags } from "@nestjs/swagger";
import { UserService } from "./user.service";
import { CurrentUser } from "./user.decorator";
import { UserSys } from "./userSys.entity";
import { UserGuard } from "src/role/role.guard";
import { DeptRoleEnum, RoleEnum } from "src/role/role.enum";
import { FindOptionsWhere, In, IsNull, Like, Not } from "typeorm";
import { userAvatarPath } from "src/util/path";
import { createReadStream, writeFileSync } from "fs";
import { Response } from "express";
import { FileInterceptor } from "@nestjs/platform-express";
import { DeptService } from "src/dept/dept.service";
import { Forbidden, Http, NotFound, PasswordErr } from "src/util/http";
import { DingtalkService } from "src/dingtalk/dingtalk.service";
import { UseLog } from "src/log/useLog.decorator";
import { cryptoPassword } from "src/util/crypto";
import { SystemService } from "src/system/system.service";




@ApiTags("用户路由")
@Controller("api/user")
@UseGuards(AuthGuard("jwt"))
export class UserController {
    constructor(
        private readonly userService: UserService,
        private readonly deptService: DeptService,
        private readonly dingtalkService: DingtalkService
    ) { }

    @Get(":phone/exists")
    @ApiOperation({ summary: "检查员工是否存在" })
    exists(
        @Param("phone") phone
    ) {
        return this.userService.userSys.exist({ where: { account: phone } });
    }
    @Post("insert")
    @UseLog("添加员工")
    @UseGuards(UserGuard([DeptRoleEnum.personnel]))
    async insert(
        @Body() { name, phone, deptid },
        @CurrentUser() currentUser: UserSys
    ) {
        const user = await this.userService.findBy({ account: phone });
        const dept = await this.deptService.dept.findOne({
            where: {
                id: deptid
            },
            relations: ["system"]
        })
        if (!dept || currentUser.system.id !== dept.system.id) throw Http.forbidden("所选部门不存在");
        if (!!user) {
            if (!!user.system || user.role !== RoleEnum.member) throw Http.forbidden("员工已存在");
            user.system = currentUser.system;
            await this.userService.userSys.save(user);
            return true;
        }
        return await this.userService.create({ phone, name, dept }, currentUser.system)
    }

    @Get(":id/avatar")
    @ApiOperation({ summary: "头像" })
    async avatar(
        @Param("id") id: number,
        @Res() res: Response
    ) {
        const path = this.userService.getUserAvatarPath(id);
        const stream = createReadStream(path)
        stream.pipe(res)
    }

    @Post("uploadAvatar")
    @ApiOperation({ summary: "上传头像" })
    @UseInterceptors(FileInterceptor("file"))
    uploadAvatar(
        @UploadedFile() file,
        @CurrentUser() user: UserSys
    ) {
        const path = userAvatarPath(user.id);
        writeFileSync(path, file.buffer);
    }

    @Get("searchAll")
    @ApiOperation({ summary: "搜索所有符合条件的员工" })
    @UseGuards(UserGuard([RoleEnum.manager, DeptRoleEnum.personnel]))
    async searchAll(
        @CurrentUser() user: UserSys,
        @Query("dept") dept: number = 0,
        @Query("name") name: string
    ) {
        const where: FindOptionsWhere<UserSys> = {}
        if (!!dept && dept != -1) where.dept = { id: dept }
        if (!!name) {
            where.user = {
                name: Like(`%${name}%`)
            }
        }
        if (user.role === RoleEnum.manager) where.dept = { id: user.dept.id };
        if (user.role !== RoleEnum.boos) {
            where.system = { id: user.system.id }
        } else {
            where.system = Not(IsNull())
        }
        const relations = ["dept", "user", "system"]
        return await this.userService.userSys.find({
            where,
            relations
        })
    }

    @Get("search")
    @ApiOperation({ summary: "搜索员工" })
    @UseGuards(UserGuard([RoleEnum.manager, DeptRoleEnum.personnel]))
    async search(
        @CurrentUser() user: UserSys,
        @Query("dept") dept: number = 0,
        @Query("page") page: number = 1,
        @Query("limit") limit: number = 10,
        @Query("name") name: string,
        @Query("info") info: string
    ) {
        if (!page) page = 1
        if (!limit) limit = 10
        const where: FindOptionsWhere<UserSys> = {
            system: {
                id: user.system.id
            }
        }
        if (!!dept && dept != -1) where.dept = { id: dept }
        if (!!name) {
            where.user = {
                name: Like(`%${name}%`)
            }
        }
        if (user.role === RoleEnum.manager) where.dept = { id: user.dept.id };
        const relations = ["dept", "user", "system"]
        const [data, count] = await this.userService.userSys.findAndCount({
            where,
            relations,
            skip: (page - 1) * limit,
            take: limit
        })
        return { count, data }
    }

    @Get("getall")
    @ApiOperation({ summary: "(测试)获取所有员工-离职信息、权限等" })
    async getall(
        @CurrentUser() user: UserSys
    ) {
        return this.userService.findsBy({
            system: {
                id: user.system.id
            }
        })
    }

    @Post("findPhone")
    @ApiOperation({ summary: "根据手机号搜索员工" })
    @UseGuards(UserGuard([DeptRoleEnum.personnel]))
    async findPhone(
        @Body() { phone }
    ) {
        const data = await this.userService.findBy({ account: phone });
        if (!!data) return data;
        const {
            errcode,
            errmsg,
            result
        } = await this.dingtalkService.getByMobile(phone);
        if (errcode !== 0) {
            return {
                errcode,
                errmsg
            }
        }
        const dingtalk = result.userid;
        const entity = await this.dingtalkService.usetGet(dingtalk);
        return await this.userService.create({
            dingtalk,
            phone: entity.result.mobile,
            name: entity.result.name,
            email: entity.email
        })
    }



    @Post("add")
    @ApiOperation({ summary: "添加员工" })
    @UseGuards(UserGuard([DeptRoleEnum.personnel]))
    async add(@Body() { id }, @CurrentUser() user: UserSys) {
        return await this.userService.userSys.update({
            id,
            system: IsNull(),
            role: RoleEnum.member
        }, {
            system: user.system
        })
    }

    @Post(":id/set")
    @UseLog("设置员工信息")
    @UseGuards(UserGuard([DeptRoleEnum.personnel]))
    async set(
        @Param("id") id: number,
        @Body() { name, ...rest }
    ) {
        const user = await this.userService.userSys.findOne({
            where: { id },
            relations: ["user"]
        })
        user.name = name;
        await this.userService.userSys.save(user);
        await this.userService.user.update({
            id: user.id
        }, {
            name,
            ...rest
        })
    }

    @Post("transfer")
    @ApiOperation({ summary: "转移部门" })
    @UseGuards(UserGuard([DeptRoleEnum.personnel]))
    async trnasfer(
        @Body() { ids, depid },
        @CurrentUser() user: UserSys
    ) {
        const dept = await this.deptService.dept.findOne({ where: { id: depid } });
        if (!dept) throw NotFound;
        return await this.userService.userSys.update({
            id: In(ids.filter(e => e != user.id)),
            system: {
                id: user.system.id
            },
            role: RoleEnum.member
        }, {
            dept
        })
    }


    @Post("del")
    @ApiOperation({ summary: "删除员工(测试)" })
    @UseGuards(UserGuard([DeptRoleEnum.personnel]))
    async del(@Body() ids: number[], @CurrentUser() user: UserSys) {
        return this.userService.userSys.remove(await this.userService.findsBy({
            id: In(ids),
            system: {
                id: user.system.id
            }
        }))
    }

    @Get(":id/initPwd")
    @UseLog("初始化密码")
    initPwd(
        @CurrentUser() user: UserSys,
        @Param("id") id: number
    ) {
        if (id === user.id) throw Forbidden
        return this.userService.userSys.update({
            id,
            role: Not(RoleEnum.boos)
        }, {
            password: cryptoPassword("123456")
        })
    }

    @Get("getBook")
    @ApiOperation({ summary: "获取通讯录" })
    async getBook(
        @CurrentUser() user: UserSys
    ) {
        const more = {
            name: "其他",
            value: []
        }
        let system: any = Not(IsNull());
        if (user.role !== RoleEnum.boos) {
            system = {
                id: user.system.id
            }
        }
        //所有特殊部门
        const book = await this.userService.findsBy({
            dept: {
                editable: false
            }
        })

        //普通员工看到自己部门的员工
        if (user.role === RoleEnum.member && (!user.dept || user.dept?.deptRole === DeptRoleEnum.member)) {
            more.value = await this.userService.findsBy({
                dept: {
                    id: user.dept.id
                }
            });
            //其他可以看到所有
        } else {
            more.value = await this.userService.findsBy({
                system,
                dept: [{
                    id: Not(IsNull()),
                    editable: true
                }]
            })
            if (user.role !== RoleEnum.boos) more.value.push(await this.userService.findBy({ role: RoleEnum.boos }))
            if (user.role !== RoleEnum.director) more.value.push(await this.userService.findBy({ role: RoleEnum.director }))
        }
        return book.concat(more.value).filter(e => !!e)
        // const book = [{
        //     name: "人事部",
        //     value: await this.userService.findsBy({
        //         system,
        //         dept: {
        //             deptRole: DeptRoleEnum.personnel
        //         }
        //     })
        // }, {
        //     name: "财务部",
        //     value: await this.userService.findsBy({
        //         system,
        //         dept: {
        //             deptRole: DeptRoleEnum.finance
        //         }
        //     })
        // }, {
        //     name: "商务部",
        //     value: await this.userService.findsBy({
        //         system,
        //         dept: {
        //             deptRole: DeptRoleEnum.business
        //         }
        //     })
        // }, more];
        // return book.map(e => {
        //     e.value = e.value.filter(a => a.id !== user.id);
        //     return e;
        // })
    }

    @Post("updPwd")
    @UseLog("修改密码")
    async updPwd(
        @Body() { password, beforePassword },
        @CurrentUser() user: UserSys
    ) {
        if (cryptoPassword(beforePassword) !== user.password) throw PasswordErr
        if (password.length < 6) throw Http.forbidden("密码长度不得小于6位")
        await this.userService.userSys.update({
            id: user.id
        }, {
            password: cryptoPassword(password)
        })
    }
}